从ES6的Proxy代理看ES5的代理如何实现
ES6的Proxy代理
Example
var person = {name:''};
var personCopy = new Proxy(person,{
get(target,key,receiver){
console.log('get方法被拦截。。。');
return Reflect.get(target,key,receiver);
},
set(target,key,value,receiver){
console.log('set方法被拦截。。。')
return Reflect.set(target,key,value,receiver);
}
})
person.name = 'arvin'; // 未有拦截日志打出
personCopy.name = 'arvin'; // set方法被拦截。。。
console.log(person.name); // 未有拦截日志打出
console.log(personCopy.name); // get方法被拦截。。。
代码解读:从上述的例子可以看出,被代理对象person的get和set不会经过代理拦截器get,set,而只有代理对象personCopy在get和set方法调用的时候才会经过拦截器,由此可见ES6的代理Proxy并不是一个类似JAVA的AOP,而其实只是将person的引用赋值给了personCopy,让代理对象personCopy和被代理对象person指向了同一个内存空间,下面是我实现的一个用ES5写的Proxy拦截,供大家参考理解Proxy实现原理提供思路:
Example:
/**浅拷贝工具方法**/
function clone(myObj){
if(typeof(myObj) != 'object' || myObj == null) return myObj;
var newObj = new Object();
for(var i in myObj){
newObj[i] = clone(myObj[i]);
}
return newObj;
}
/*代理实现类*/
function ProxyCopy(target,handle){
var targetCopy = clone(target);
Object.keys(targetCopy).forEach(function(key){
Object.defineProperty(targetCopy, key, {
get: function() {
return handle.get && handle.get(target,key);
},
set: function(newVal) {
handle.set && handle.set();
target[key] = newVal;
}
});
})
return targetCopy;
}
var person = {name:''};
var personCopy = new ProxyCopy(person,{
get(target,key){
console.log('get方法被拦截。。。');
return target[key];
},
set(target,key,value){
console.log('set方法被拦截。。。')
// return true;
}
})
person.name = 'arvin'; // 未有拦截日志打出
personCopy.name = 'arvin'; // set方法被拦截。。。
console.log(person.name); // 未有拦截日志打出
console.log(personCopy.name); // get方法被拦截。。。
ES5对Proxy代理的实现
要说到ES5的代理实现,其中比较有名的就算是vue的双向绑定中到了get和set的代理拦截实现了,下面是一个仿照该技术的一个实现:
Example
// 拦截器
function Observer(data) {
this.data = data;
this.walk(data);
}
(function($Observer){
$Observer.prototype = {
walk: function(data) {
var me = this;
Object.keys(data).forEach(function(key) {
me.convert(key, data[key]);
});
},
convert: function(key, val) {
this.defineReactive(this.data, key, val);
},
defineReactive: function(data, key, val) {
var childObj = observe(val);
Object.defineProperty(data, key, {
enumerable: true, // 可枚举
configurable: false, // 不能再define
get: function() {
return val;
},
set: function(newVal) {
if (newVal === val) {
return;
}
val = newVal;
console.log("新的值是object的话,进行监听");
console.log("通知订阅者");
dep.notify();
}
});
}
};
})(Observer);
// 拦截器的出口
function observe(value) {
if (!value || typeof value !== 'object') {
return;
}
return new Observer(value);
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。